using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace BardsTaleViewer {
  public class Picture_Atari : IPicture {
    public Bitmap _bitmap;
    public IAnims _anims;
    public static byte [] _dumpCityTree = ExtensionByte.CreateFromFile ("Files/B1 Atari/CITYTREE");

    public static byte [] _dumpAtari = Properties.Resources.Atari_dump.Extract (0);

    public Picture_Atari (Bitmap bitmap, IAnims anims) {
      _bitmap = bitmap;
      _anims = anims;
    }

    public static Picture_Atari Load (byte [] dump, int pictureIndex) {
      int offset = pictureIndex * 4;
      offset = (int) dump.ReadLong (offset);
      int offsetNext = (int) dump.ReadLong (pictureIndex * 4 + 4);
      int srcRead = offset;
      int sizeSrcComputed = offsetNext - offset;
      //int sizeDst = (int) dump.ReadLong (ref offset);
      //int unk = (int) dump.ReadLong (ref offset);

      int offsetBufferTree = 8;
      Huffman huffman = new Huffman (_dumpCityTree, ref offsetBufferTree, Computer.Atari);

      //CheckTree (huffman, Properties.Resources.Tree_Atari, 10, 0x34E62-10, Computer.Atari);

      huffman._currentMask = 0x80;
      huffman._currentValue = dump.ReadByte (ref offset);

      byte [] a = huffman.Decode_Atari (dump, ref offset, 20);
      //a.WriteToFile ("Atari a.dmp");
      //byte [] b = huffman.Decode_Atari (dump, ref offset, size - 20);
      // 112x88 / 2 = 4928
      byte [] b = huffman.Decode_Atari (dump, ref offset, 4928);
      //b.WriteToFile ("Atari b.dmp");

      int [] paletteData = new int [] { 0x000, 0x200, 0x555, 0x222, 0x000, 0x031, 0x471, 0x407, 0x037, 0x700, 0x740, 0x770, 0x005, 0x500, 0x600, 0x777 };
      paletteData [1] = a.ReadWord (0 * 2);
      paletteData [7] = a.ReadWord (1 * 2);
      paletteData [8] = a.ReadWord (2 * 2);
      paletteData [9] = a.ReadWord (3 * 2);
      paletteData [10] = a.ReadWord (4 * 2);
      paletteData [11] = a.ReadWord (5 * 2);
      paletteData [12] = a.ReadWord (6 * 2);
      paletteData [13] = a.ReadWord (7 * 2);
      paletteData [14] = a.ReadWord (8 * 2);
      paletteData [4] = 0x700;
      paletteData [5] = 0x770;

      paletteData [6] = a.ReadWord (9 * 2);
      Palette palette = new Palette (paletteData, Palette.LookupTypeEnum.ST);

      //Palette palette = new Palette (a, 0, 16, Palette.LookupTypeEnum.Amiga);
      //int offsetSrc = 0;
      //for (int i = 0; ; i++) {
      //  if (offsetSrc == b.Length)
      //    break;
      //byte [] bb = RLE.Decode (b, ref offsetSrc);
      //bb.WriteToFile ("bb.dmp");
      Bitmap bitmap = SpriteReader.CreateBitmap (b, 0, 112, 88, 4, SpriteReader.ModesEnum.Interleaved, 2, palette, 0, SpriteReader.MasksEnum.Opaque);
      //bitmap.Save (string.Format ("Picture {0} Atari.png", pictureIndex.ToString ().PadLeft (2, '0')), ImageFormat.Png);
      //}
      //if ((offset % 2) == 1)
      //  offset++;

      byte [] c = new byte [0];
      for (int i = 0; ; i++) {
        int size = huffman.Decode_Atari (dump, ref offset, 2).ReadWord (0);
        if (size == 0)
          break;
        c = c.Append (huffman.Decode_Atari (dump, ref offset, size));

      }
      srcRead = offset - srcRead;
      //Console.WriteLine (c.Dump (0, c.Length, 0, 1, 16, false));
      //c.WriteToFile ("Atari anim.dmp");
      //if ((sizeSrcComputed != srcRead) &&
      //  (sizeSrcComputed != (srcRead - 1)) &&
      //  (sizeSrcComputed != (srcRead - 2)))
      //  throw new Exception ();

      int offsetAnim = 0;
      IAnims anims = new Anims_Atari (c, ref offsetAnim, pictureIndex);

      anims.CreateBitmaps (bitmap, palette, b);
      return (new Picture_Atari (bitmap, anims));
    }

    public static void CheckTree (Huffman huffman, byte [] dump, int start, int baseOffset, Computer computer) {
      for (int i = 0; i < 768; i++) {
        long a = huffman._tree.ReadLong (i * 10 + 0 + start);
        if (a == 0xFFFFFFFF)
          a = 0;
        else
          a += baseOffset;
        long b = huffman._tree.ReadLong (i * 10 + 4 + start);
        if (b == 0xFFFFFFFF)
          b = 0;
        else
          b += baseOffset;
        int c = huffman._tree.ReadByte (i * 10 + 8 + start);

        long aa = dump.ReadLong (i * 10 + 0);
        long bb = dump.ReadLong (i * 10 + 4);
        int cc;
        if (computer == Computer.Amiga)
          cc = dump.ReadByte (i * 10 + 8);
        else
          cc = dump.ReadByte (i * 10 + 9);

        if ((aa != 0) || (bb != 0))
          cc = 0;

        //if ((a == 0) && (b == 0) && (c == 0)) {
        //  if ((aa != 0) || (bb != 0))
        //    throw new Exception ();
        //  break;
        //}

        if ((a != aa) || (b != bb) || (c != cc))
          throw new Exception ();

        Console.WriteLine ("{6,4} {0:X8} {1:X8} {2:X2}    {3:X8} {4:X8} {5:X2}", a, b, c, aa, bb, cc, i);
      }
    }

    public Bitmap Bitmap {
      get {
        return (_bitmap);
      }
    }

    public List<IAnim> Anims {
      get {
        if (_anims == null)
          return (null);
        return (_anims.Anims);
      }
    }

    public static string GetName (int pictureIndex) {
      if (pictureIndex == 35)
        return ("(Harkyn's Castle)");
      else if (pictureIndex == 42)
        return ("(Temple)");
      else if (pictureIndex == 43)
        return ("(Tavern)");
      else if (pictureIndex == 45)
        return ("(Armory)");
      else if (pictureIndex == 52)
        return ("(Guild)");

      List<string> specialsList = new List<string> ();
      if (pictureIndex <= 9) {
        int offsetClassesName = 0x2E3B6;
        int offsetClassName = (int) _dumpAtari.ReadLong (offsetClassesName + pictureIndex * 4);
        string className = _dumpAtari.ReadString (offsetClassName);
        specialsList.Add (className);
      }
      else if (pictureIndex == 10) {
        specialsList.Add ("Treasure!");
        specialsList.Add ("High Priest's treasure");
      }
      else if (pictureIndex == 11)
        specialsList.Add ("Sorry, bud");
      else if (pictureIndex == 12) {
        specialsList.Add ("Magic mouth");
        specialsList.Add ("Mouth...");
      }
      else if (pictureIndex == 23)
        specialsList.Add ("Guard Captain");
      else if (pictureIndex == 25)
        specialsList.Add ("Keymaster");
      else if (pictureIndex == 26)
        specialsList.Add ("Spidergod");
      else if (pictureIndex == 29)
        specialsList.Add ("Bashar Kavilor");
      else if (pictureIndex == 36) {
        specialsList.Add ("Mangar's tower");
        specialsList.Add ("Kylearan's tower");
      }
      else if (pictureIndex == 37) {
        specialsList.Add ("Statue of a Samurai warrior");
        specialsList.Add ("Statue of a Stone giant");
        specialsList.Add ("Statue of an Ogre Lord");
        specialsList.Add ("Stone Golem");
        specialsList.Add ("Statue of a Grey Dragon");
      }
      else if (pictureIndex == 38)
        specialsList.Add ("City Gate");
      else if (pictureIndex == 40)
        specialsList.Add ("Witch King");
      else if (pictureIndex == 46)
        specialsList.Add ("Old statue");
      else if (pictureIndex == 47)
        specialsList.Add ("The guild");
      else if (pictureIndex == 49)
        specialsList.Add ("Robed Men");
      else if (pictureIndex == 51)
        specialsList.Add ("Bard's Tale");
      else if (pictureIndex == 53)
        specialsList.Add ("Kylearan");
      else if (pictureIndex == 54)
        specialsList.Add ("Chest");
      else if (pictureIndex == 55)
        specialsList.Add ("Garth's Equipment Shoppe");
      else if (pictureIndex == 56)
        specialsList.Add ("Review board");
      else if (pictureIndex == 57) {
        specialsList.Add ("Amber Tower");
        specialsList.Add ("Mangar's Tower");
      }
      else if (pictureIndex == 58) {
        specialsList.Add ("1OO Blessings");
        specialsList.Add ("Great gods");
        specialsList.Add ("Greater gods");
        specialsList.Add ("Thief Temple");
        specialsList.Add ("Tmpl of Kiosk");
        specialsList.Add ("Greatest gods");
        specialsList.Add ("Mad God");
      }
      else if (pictureIndex == 59)
        specialsList.Add ("Roscoe's Energy Emporium");
      else if (pictureIndex == 60)
        specialsList.Add ("Harkyn's Castle");
      else if (pictureIndex == 61)
        specialsList.Add ("Empty building");
      else if (pictureIndex == 62) {
        specialsList.Add ("Scarlet Bard");
        specialsList.Add ("Sinister Inn");
        specialsList.Add ("Dragonbreath");
        specialsList.Add ("Ask Y'Mother");
        specialsList.Add ("Archmage Inn");
        specialsList.Add ("Skull Tavern");
        specialsList.Add ("Drawnblade");
        specialsList.Add ("Tavern");
      }

      // 0-127
      int offsetMonstersNamePointer = 0x3095C;
      // 1-128
      int offsetMonstersPictureIndex = 0x2EDD0;

      List<string> monstersNameList = new List<string> ();
      for (int i = 0; i < 128; i++) {
        int pictureIndexTemp = _dumpAtari.ReadByte (1 + offsetMonstersPictureIndex + i);
        if (pictureIndexTemp == pictureIndex) {
          int offsetMonsterName = (int) _dumpAtari.ReadLong (offsetMonstersNamePointer + i * 4);
          string monsterName = _dumpAtari.ReadString (offsetMonsterName);
          string [] split = monsterName.Split ('^');
          if (split.Length > 1)
            monsterName = split [0] + split [1];
          if (!monstersNameList.Contains (monsterName))
            monstersNameList.Add (monsterName);
        }
      }

      string specials = null;
      if (specialsList.Count != 0) {
        specials = "";
        foreach (string special in specialsList) {
          if (specials != "")
            specials += "<br />";
          specials += "[" + special + "]";
        }
      }

      string monstersName = null;
      if (monstersNameList.Count != 0) {
        monstersName = "";
        foreach (string monsterName in monstersNameList) {
          if (monstersName != "")
            monstersName += "<br />";
          monstersName += monsterName;
        }
      }

      if ((specials != null) && (monstersName != null))
        return (specials + "<br />" + monstersName);

      if ((specials == null) && (monstersName == null))
        return ("?");

      if (specials != null)
        return (specials);

      return (monstersName);
    }
  }
}
